#include "TimerManager.h"
#include <stdlib.h>
#include "LinkList.h"

//定时节点结构体
struct timer_node {
    LIST_NODE list;   //侵入式链表节点变量，尽量放到结构体首位置。
    timer_node_state_t state;   //定时器状态
    timer_node_mode_t mode;     //定时器模式
    uint32_t timeout_ms;     // 总定时 ms：用户设置的定时时间（单位：ms）
    uint32_t remaining_ms;   // 剩余 ms：当前剩余的计时 ms（递减至0触发）
    timer_event_t event;        //回调函数的指针，参数需要用户来识别
    void* user_data;            //回调函数的参数，需要用户管理
}; 

//定时器节点管理器
static LIST_MANAGE timer_Manager;

/// @brief 定时器初始化
/// @param 无
void timer_manager_init(void)
{
	//初始化链表管理器
	ListManageInit(&timer_Manager);
}

/// @brief 申请定时器节点，并定死定时模式
/// @param mode 定时模式，单次还是循环触发
/// @param timeout_func 定时事件回调函数指针
/// @param user_data 可以传入给回调函数的数据指针，可以NULL
/// @return 系统分配的定时节点，分配失败返回NULL
timer_node_t *timer_manager_creat(timer_node_mode_t mode, 
									timer_event_t timeout_func,  
									void* user_data)
{
	//分配定时器节点内存
	timer_node_t *tm_node = malloc(sizeof(timer_node_t));

	if(tm_node == NULL) {
		return NULL;
	}

	//更新结构体参数
	tm_node->mode = mode;
	tm_node->event = timeout_func;
	tm_node->user_data = user_data;

	return tm_node;
}

/// @brief 启动定时器，并设置超时时间，插入链表中；如果想临时修改时间，也可以调用此函数
/// @param tm_node 定时器节点指针
/// @param timeout_ms 超时时间
/// @return 运行是否成功
bool timer_manager_start(timer_node_t *tm_node, uint32_t timeout_ms)
{
	if(tm_node == NULL) {
		return false;
	}

	tm_node->timeout_ms = timeout_ms;	//记录定时周期
	tm_node->remaining_ms = timeout_ms;	//重置剩余时间

	tm_node->state = TIMER_NODE_RUNNING;//启用定时器
	
	//节点插入到链表里边
	if(ListPutHead(&timer_Manager,(LIST_NODE *)tm_node) != L_OK) {
		free(tm_node);
		return NULL;
	}
	
	return true;
}

/// @brief 定时器停止运行，并从链表中删除
/// @param timer 定时器节点指针 
void timer_manager_stop(timer_node_t* tm_node)
{
	if(tm_node == NULL) {
		return ;
	}

	tm_node->state = TIMER_NODE_STOPPED;//关闭定时器
	
	//从链表中删除节点
	ListPopItem(&timer_Manager, (LIST_NODE *)tm_node);
}

/// @brief 删除定时器节点，释放节点
/// @param timer 定时器节点
void timer_manager_delete(timer_node_t* tm_node)
{
	if(tm_node == NULL) {
		return ;
	}
	//停止定时器
	timer_manager_stop(tm_node);
	
	//释放内存
	free(tm_node);
}

/// @brief 放置到1ms定时器中断里边，自动扫描定时节点并执行回调函数，回调函数不要阻塞定时器
/// @param  空
void timer_manager_run(void)
{
	timer_node_t *tm_node = (timer_node_t *)timer_Manager.head; //获取第一个节点

	while(tm_node != NULL) {
		timer_node_t* next =vListPeekNext((LIST_NODE *)tm_node); //提前获取下一个节点，防止删除节点后无法获取
		
		if(tm_node->state == TIMER_NODE_RUNNING) { 	//运行状态
			if(tm_node->remaining_ms == 0) {					//定时时间到
				if(tm_node->event != NULL) {
					tm_node->event(tm_node->user_data); 	//执行回调
					tm_node->remaining_ms = tm_node->timeout_ms;
					
					//如果单次触发，则修改状态为stop
					if(tm_node->mode == TIMER_NODE_ONE_SHOT) {
						timer_manager_stop(tm_node);
					}
				}
			}
			tm_node->remaining_ms--; //剩余时间-1,
		}

		tm_node = next; //获取下一个节点
	}
}
